/*
 * @Author: your name
 * @Date: 2021-03-09 11:35:46
 * @LastEditTime: 2021-09-02 19:12:00
 * @LastEditors: your name
 * @Description: In User Settings Edit
 * @FilePath: /04 Queues/queue.c
 */
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include "queue.h"

// Creates an empty queue whose capacity is size
bool CreateQueue(Queue *queue, int size) {
  if(size < 1) {
    printf("Error: size should be positive.\n");
    return false;
  }
  queue->values = (double*)malloc(sizeof(double) * size);
  queue->front = 0;
  queue->rear = -1;
  queue->counter = 0;
  queue->maxSize = size;
  return true;
}

// Returns true if the queue is empty and false otherwise
bool IsEmpty(Queue *queue) {
  return queue->counter == 0;
}

// Returns true if the queue is full and false otherwise
bool IsFull(Queue *queue) {
  return queue->counter == queue->maxSize;
}

// Adds a new element with value x to the rear of the queue
bool Enqueue(Queue *queue, double x) {
  if(IsFull(queue)) {
    printf("Error: the queue is full.\n");
    return false;
  }
  queue->rear = (queue->rear + 1) % queue->maxSize;
  queue->values[queue->rear] = x;
  queue->counter++;
  return true;
}

// Removes an element from the front of the queue
// Passes the value of the front element to x
bool Dequeue(Queue *queue, double *x) {
  if(IsEmpty(queue)) {
    printf("Error: the queue is empty.\n");
    return false;
  }
  *x = queue->values[queue->front]; // pass the value to x
  queue->front = (queue->front + 1) % queue->maxSize;
  queue->counter--;
  return true;
}

// Prints all the elements of the queue
void DisplayQueue(Queue *queue) {
  printf("front --> ");
  for(int i = 0; i < queue->counter; i++) {
    int j = (queue->front + i) % queue->maxSize;
    printf("%f%s", queue->values[j], j != queue->rear ? "\n          " : "");
  }
  printf(" <-- rear\n");
}

// Frees the memory occupied by the queue
void DestroyQueue(Queue *queue) {
  free(queue->values);
  // setting pointer to null is a good practice
  // to prevent illegal memory access after free(pointer)
  queue->values = NULL;
  queue->front = 0;
  queue->rear = -1;
  queue->counter = 0;
}


int main(void) {
  Queue queue;
  double value;
  CreateQueue(&queue, 5);
  puts("Enqueue 5 items.");
  for(int x = 0; x < 5; x++)
    Enqueue(&queue, x);
  puts("Now attempting to enqueue again...");
  Enqueue(&queue, 5.0);
  DisplayQueue(&queue);
  Dequeue(&queue, &value);
  printf("Retrieved element = %f\n", value);
  DisplayQueue(&queue);
  Enqueue(&queue, 7.0);
  DisplayQueue(&queue);
  DestroyQueue(&queue);
  return 0;
}
